package com.sky.sd.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.sd.common.exception.ServiceException;
import com.sky.sd.system.bean.dto.LoginUser;
import com.sky.sd.system.bean.dto.UserDto;
import com.sky.sd.system.bean.po.Menu;
import com.sky.sd.system.bean.po.Role;
import com.sky.sd.system.bean.po.RoleUser;
import com.sky.sd.system.bean.po.User;
import com.sky.sd.system.bean.vo.*;
import com.sky.sd.system.constant.SystemConstant;
import com.sky.sd.system.dao.MenuMapper;
import com.sky.sd.system.dao.RoleMapper;
import com.sky.sd.system.dao.RoleUserMapper;
import com.sky.sd.system.dao.UserMapper;
import com.sky.sd.system.enums.UserIsSysType;
import com.sky.sd.system.enums.MenuType;
import com.sky.sd.system.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author 弓振
 * @since 2020-06-30
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleUserMapper roleUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public LoginUser getLoginUserByUsername(String username) {
        LoginUser loginUser = new LoginUser();
        Optional<User> userOpt = new LambdaQueryChainWrapper<User>(baseMapper).eq(User::getUserName, username).oneOpt();
        if (userOpt.isPresent()) {
            // 查询角色
            List<Role> roles = roleMapper.listRolesByUserId(userOpt.get().getId());
            BeanUtils.copyProperties(userOpt.get(), loginUser);
            loginUser.setRoles(roles);

            // 查询权限
            if (CollectionUtils.isNotEmpty(roles)) {
                Set<String> roleIds = roles.parallelStream().map(role -> role.getId()).collect(Collectors.toSet());
                List<Menu> menus = menuMapper.listMenusByRoleIds(roleIds, MenuType.BUTTON);
                Set<String> perms = menus.parallelStream().map(menu -> menu.getCode()).filter(menu -> StringUtils.isNotBlank(menu)).collect(Collectors.toSet());
                loginUser.setPerms(perms);
            } else {
                loginUser.setPerms(new HashSet<>());
            }
            return loginUser;
        }
        return null;
    }

    @Override
    public IPage<UserDto> listUserPage(UserSearchVo vo) {
        IPage<UserDto> page = new Page<>(vo.getPageNum(), vo.getPageSize());
        return baseMapper.listUserPage(page, vo);
    }

    @Override
    @Transactional
    public void add(UserAddVo vo) {
        User user = new User();
        BeanUtils.copyProperties(vo, user);
        user.setIsSys(UserIsSysType.COMM.getType());
        user.setPassword(passwordEncoder.encode(SystemConstant.INIT_PASSWOR));
        baseMapper.insert(user);
    }

    @Override
    @Transactional
    public void update(UserUpdateVo vo) {
        // 是否允许修改
        canUpdate(vo.getId());

        // 修改用户
        User user = new User();
        BeanUtils.copyProperties(vo, user);
        baseMapper.updateById(user);
    }

    @Override
    @Transactional
    public void delete(DeleteVo vo) {
        // 是否允许删除
        String id = vo.getIds().iterator().next();
        canUpdate(id);

        // 删除用户
        baseMapper.deleteById(id);
    }

    @Override
    public Set<String> userOfRoles(String userId) {
        List<Role> roles = roleMapper.listRolesByUserId(userId);
        Set<String> roleIds = roles.parallelStream().map(role -> role.getId()).collect(Collectors.toSet());
        return roleIds;
    }

    @Override
    @Transactional
    public void userToRoles(UserToRolesVo vo) {
        // 是否允许修改
        canUpdate(vo.getId());

        // 重新分配角色
        roleUserMapper.delete(Wrappers.<RoleUser>lambdaQuery().eq(RoleUser::getUserId, vo.getId()));
        vo.getRoleIds().parallelStream().forEach(roleId -> {
            roleUserMapper.insert(RoleUser.builder().userId(vo.getId()).roleId(roleId).build());
        });
    }

    private void canUpdate(String id) {
        User oldUser = baseMapper.selectById(id);
        if(oldUser == null) {
            throw new ServiceException("修改的用户不存在");
        }

        if(!ObjectUtils.notEqual(oldUser.getIsSys(), UserIsSysType.SUPER_ADMIN.getType())) {
            throw new ServiceException("超级管理员不能修改");
        }
    }
}
